import { debugLogger } from "../common/logger";
import { InsertSortedArray } from "../utils";

export interface DepthCache {
  price: number;
  quantity: number;
  // 标记时间，过期删除
  t: number;
  /** usdt value  */
  sum: number;
}
export interface Bid {
  price: number;
  quantity: number;
}

export interface Depth {
  symbol: string;
  bids: Bid[] | [string, string][];
  asks: Bid[] | [string, string][];
  timestamp: number;
}

const H_48 = 172800000;
const H_12 = 43200000;

export class OrderBook {
  static getPrice = (item: Bid | [string, string]) => Array.isArray(item) ? Number(item[0]) : item.price;
  static getAmount = (item: Bid | [string, string]) => Array.isArray(item) ? Number(item[1]) : item.quantity;
  private depthMap: Record<string, {
    bids: Bid[];
    asks: Bid[];
    currentPrice: number;
  }>
  /** 缓存数据，可能会有 */
  private depthCache: Record<string, {
    bids: Record<string, DepthCache>,
    asks: Record<string, DepthCache>,
  }>;
  constructor() {
    this.depthCache = {};
    this.depthMap = {};
  }
  init(symbol: string) {
    this.depthCache[symbol] = {
      bids: {} as any,
      asks: {} as any,
    }
    this.depthMap[symbol] = {
      bids: [],
      asks: [],
      currentPrice: 0,
    }
  }
  public getBook(symbol: string) {
    return this.depthMap[symbol] || { asks: [], bids: [] };
  }
  public getTracePrice(symbol: string, dis = 0.09) {
    const { bids, asks } = this.getBook(symbol);
    const currentPrice = this.depthMap[symbol] ? this.depthMap[symbol].currentPrice : (bids[bids.length - 1].price + asks[0].price) / 2;

    if (this.depthMap[symbol]) {
      debugLogger(this.depthMap[symbol].currentPrice)
    }
    const filter = (item: Bid) => {
      if (item.price > currentPrice * (1 + dis)|| item.price < currentPrice * (1 - dis)) {
        return false;
      }
      return true;
    };
    const sortedBids = bids.filter(filter).sort(function (a, b) {
      return OrderBook.getAmount(b) - OrderBook.getAmount(a);
    }).slice(0, 6);
    const sortedAsks = asks.filter(filter).sort(function (a, b) {
      return OrderBook.getAmount(b) - OrderBook.getAmount(a);
    }).slice(0, 6);

    const buyPrices = sortedBids.map(item => OrderBook.getPrice(item)).sort((a, b) => b - a);
    const sellPrices = sortedAsks.map(item => OrderBook.getPrice(item)).sort((a, b) => a - b);
    return {
      sell: sellPrices,
      buy: buyPrices,
    };
  }

  public process(data: Depth, f?: boolean) {
    if (Array.isArray(data.bids) && Array.isArray(data.asks)) {
      // 初始化
      if (this.depthCache[data.symbol] === undefined) {
        this.init(data.symbol);
      }
      const depthCache = this.depthCache[data.symbol];

      this.depthMap[data.symbol].bids = this.getDepthFromCache('bids', depthCache, data);
      if (f) {
        console.log(this.depthMap[data.symbol].bids)
      }

      this.depthMap[data.symbol].asks = this.getDepthFromCache('asks', depthCache, data);
    }
  }
  public getCurrentPrice = (symbol: string) => {
    return this.depthMap[symbol].currentPrice;
  }
  private getDepthFromCache(type: 'asks' | 'bids', depthCache: { bids: Record<string, DepthCache>; asks: Record<string, DepthCache> }, newData: Depth) {
    const newBids = type === 'bids' ? newData.bids : newData.asks;
    const cache = type === 'bids' ? depthCache.bids : depthCache.asks;
    const isUSDT = newData.symbol.endsWith('USDT');

    // if (!newBids[0]) {
    //   console.log(newBids[0]);
    // }
    const currentPrice = this.depthMap[newData.symbol].currentPrice;
    const removeByPrice = (element: DepthCache) => {
      if (currentPrice == null) {
        // 12h
        return element.t < Date.now() - H_12
      }
      // 48h
      if (element.t < Date.now() - H_48) {
        return true
      }
      return type === 'bids' ? currentPrice < element.price : currentPrice > element.price;
    }
    // 更新缓存数据 (@TODO build类型错误)
    (newBids as any[]).forEach((item: [string, string] | Bid) => {
      const price = Array.isArray(item) ? Number(item[0]) : item.price;
      const quantity = Array.isArray(item) ? Number(item[1]) : item.quantity;
      const sum = isUSDT ? Number(quantity) * Number(price) : 0;
      if (Number(quantity) == 0 || (isUSDT && sum < 5000)) {
        delete cache[price];
      } else {
        cache[price] = {
          price: Number(price),
          quantity: Number(quantity),
          t: newData.timestamp,
          sum
        }
      }
    });
    // 根据缓存数据生成新的数据
    const newList = new InsertSortedArray<Bid>({ key: 'price', order: type === 'asks' ? 'asc' : 'asc' });
    for (const price in cache) {
      if (Object.prototype.hasOwnProperty.call(cache, price)) {
        const element = cache[price];
        // 超过30分钟的数据删除
        if (removeByPrice(element)) {
          delete cache[price];
        } else {
          newList.add(element);
        }
      }
    }
    return newList.getArray();
  }
  public updatePrice(symbol: string, close: number) {
    if (this.depthMap[symbol] === undefined) {
      this.init(symbol);
    }
    this.depthMap[symbol].currentPrice = close;
  }
  public destroy () {
    this.depthCache = null;
    this.depthMap = null;
  }
}